package j2me.util.collections;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */


public abstract class AbstractCollection implements Collection {

    /**
     * Sole constructor. (For invocation by subclass constructors, typically
     * implicit.)
     */
    protected AbstractCollection() {
    }

    // Query Operations
    /**
     * Returns an iterator over the elements contained in this collection.
     *
     * @return an iterator over the elements contained in this collection.
     */
    public abstract Iterator iterator();

    /**
     * Returns the number of elements in this collection. If the collection
     * contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
     * <tt>Integer.MAX_VALUE</tt>.
     *
     * @return the number of elements in this collection.
     */
    public abstract int size();

    /**
     * Returns <tt>true</tt> if this collection contains no elements.<p>
     *
     * This implementation returns <tt>size() == 0</tt>.
     *
     * @return <tt>true</tt> if this collection contains no elements.
     */
    public boolean isEmpty() {
        return size() == 0;
    }

    /**
     * Returns <tt>true</tt> if this collection contains the specified element.
     * More formally, returns <tt>true</tt> if and only if this collection
     * contains at least one element <tt>e</tt> such that <tt>(o==null ? e==null
     * : o.equals(e))</tt>.<p>
     *
     * This implementation iterates over the elements in the collection,
     * checking each element in turn for equality with the specified element.
     *
     * @param o object to be checked for containment in this collection.
     * @return <tt>true</tt> if this collection contains the specified element.
     */
    public boolean contains(Object o) {
        Iterator e = iterator();
        if (o == null) {
            while (e.hasNext()) {
                if (e.next() == null) {
                    return true;
                }
            }
        } else {
            while (e.hasNext()) {
                if (o.equals(e.next())) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Returns an array containing all of the elements in this collection. If
     * the collection makes any guarantees as to what order its elements are
     * returned by its iterator, this method must return the elements in the
     * same order. The returned array will be "safe" in that no references to it
     * are maintained by the collection. (In other words, this method must
     * allocate a new array even if the collection is backed by an Array). The
     * caller is thus free to modify the returned array.<p>
     *
     * This implementation allocates the array to be returned, and iterates over
     * the elements in the collection, storing each object reference in the next
     * consecutive element of the array, starting with element 0.
     *
     * @return an array containing all of the elements in this collection.
     */
    public Object[] toArray() {
        Object[] result = new Object[size()];
        Iterator e = iterator();
        for (int i = 0; e.hasNext(); i++) {
            result[i] = e.next();
        }
        return result;
    }

    /**
     * Returns an array containing all of the elements in this collection; the
     * runtime type of the returned array is that of the specified array. If the
     * collection fits in the specified array, it is returned therein.
     * Otherwise, a new array is allocated with the runtime type of the
     * specified array and the size of this collection.<p>
     *
     * If the collection fits in the specified array with room to spare (i.e.,
     * the array has more elements than the collection), the element in the
     * array immediately following the end of the collection is set to
     * <tt>null</tt>. This is useful in determining the length of the collection
     * <i>only</i> if the caller knows that the collection does not contain any
     * <tt>null</tt> elements.)<p>
     *
     * If this collection makes any guarantees as to what order its elements are
     * returned by its iterator, this method must return the elements in the
     * same order. <p>
     *
     * This implementation checks if the array is large enough to contain the
     * collection; if not, it allocates a new array of the correct size and type
     * (using reflection). Then, it iterates over the collection, storing each
     * object reference in the next consecutive element of the array, starting
     * with element 0. If the array is larger than the collection, a
     * <tt>null</tt> is stored in the first location after the end of the
     * collection.
     *
     * @param a the array into which the elements of the collection are to be
     * stored, if it is big enough; otherwise, a new array of the same runtime
     * type is allocated for this purpose.
     * @return an array containing the elements of the collection.
     *
     * @throws NullPointerException if the specified array is <tt>null</tt>.
     *
     * @throws ArrayStoreException if the runtime type of the specified array is
     * not a supertype of the runtime type of every element in this collection.
     */
    public Object[] toArray(Object a[]) {
        int size = size();
        
        if (a.length < size) {
            a =  new Object[size];
        }

        Iterator it = iterator();
        for (int i = 0; i < size; i++) {
            a[i] = it.next();
        }

        if (a.length > size) {
            a[size] = null;
        }

        return a;
    }

    // Modification Operations
    /**
     * Ensures that this collection contains the specified element (optional
     * operation). Returns <tt>true</tt> if the collection changed as a result
     * of the call. (Returns <tt>false</tt> if this collection does not permit
     * duplicates and already contains the specified element.) Collections that
     * support this operation may place limitations on what elements may be
     * added to the collection. In particular, some collections will refuse to
     * add <tt>null</tt> elements, and others will impose restrictions on the
     * type of elements that may be added. Collection classes should clearly
     * specify in their documentation any restrictions on what elements may be
     * added.<p>
     *
     * This implementation always throws an
     * <tt>UnsupportedOperationException</tt>.
     *
     * @param o element whose presence in this collection is to be ensured.
     * @return <tt>true</tt> if the collection changed as a result of the call.
     *
     * @throws UnsupportedOperationException if the <tt>add</tt> method is not
     * supported by this collection.
     *
     * @throws NullPointerException if this collection does not permit
     * <tt>null</tt> elements, and the specified element is <tt>null</tt>.
     *
     * @throws ClassCastException if the class of the specified element prevents
     * it from being added to this collection.
     *
     * @throws IllegalArgumentException if some aspect of this element prevents
     * it from being added to this collection.
     */
    public boolean add(Object o) {
        throw new UnsupportedOperationException();
    }

    /**
     * Removes a single instance of the specified element from this collection,
     * if it is present (optional operation). More formally, removes an element
     * <tt>e</tt> such that <tt>(o==null ? e==null : o.equals(e))</tt>, if the
     * collection contains one or more such elements. Returns <tt>true</tt> if
     * the collection contained the specified element (or equivalently, if the
     * collection changed as a result of the call).<p>
     *
     * This implementation iterates over the collection looking for the
     * specified element. If it finds the element, it removes the element from
     * the collection using the iterator's remove method.<p>
     *
     * Note that this implementation throws an
     * <tt>UnsupportedOperationException</tt> if the iterator returned by this
     * collection's iterator method does not implement the <tt>remove</tt>
     * method and this collection contains the specified object.
     *
     * @param o element to be removed from this collection, if present.
     * @return <tt>true</tt> if the collection contained the specified element.
     * @throws UnsupportedOperationException if the <tt>remove</tt> method is
     * not supported by this collection.
     */
    public boolean remove(Object o) {
        Iterator e = iterator();
        if (o == null) {
            while (e.hasNext()) {
                if (e.next() == null) {
                    e.remove();
                    return true;
                }
            }
        } else {
            while (e.hasNext()) {
                if (o.equals(e.next())) {
                    e.remove();
                    return true;
                }
            }
        }
        return false;
    }

    // Bulk Operations
    /**
     * Returns <tt>true</tt> if this collection contains all of the elements in
     * the specified collection. <p>
     *
     * This implementation iterates over the specified collection, checking each
     * element returned by the iterator in turn to see if it's contained in this
     * collection. If all elements are so contained <tt>true</tt> is returned,
     * otherwise <tt>false</tt>.
     *
     * @param c collection to be checked for containment in this collection.
     * @return <tt>true</tt> if this collection contains all of the elements in
     * the specified collection.
     * @throws NullPointerException if the specified collection is null.
     *
     * @see #contains(Object)
     */
    public boolean containsAll(Collection c) {
        Iterator e = c.iterator();
        while (e.hasNext()) {
            if (!contains(e.next())) {
                return false;
            }
        }

        return true;
    }

    /**
     * Adds all of the elements in the specified collection to this collection
     * (optional operation). The behavior of this operation is undefined if the
     * specified collection is modified while the operation is in progress.
     * (This implies that the behavior of this call is undefined if the
     * specified collection is this collection, and this collection is
     * nonempty.) <p>
     *
     * This implementation iterates over the specified collection, and adds each
     * object returned by the iterator to this collection, in turn.<p>
     *
     * Note that this implementation will throw an
     * <tt>UnsupportedOperationException</tt> unless <tt>add</tt> is overridden
     * (assuming the specified collection is non-empty).
     *
     * @param c collection whose elements are to be added to this collection.
     * @return <tt>true</tt> if this collection changed as a result of the call.
     * @throws UnsupportedOperationException if this collection does not support
     * the <tt>addAll</tt> method.
     * @throws NullPointerException if the specified collection is null.
     *
     * @see #add(Object)
     */
    public boolean addAll(Collection c) {
        boolean modified = false;
        Iterator e = c.iterator();
        while (e.hasNext()) {
            if (add(e.next())) {
                modified = true;
            }
        }
        return modified;
    }

    /**
     * Removes from this collection all of its elements that are contained in
     * the specified collection (optional operation). <p>
     *
     * This implementation iterates over this collection, checking each element
     * returned by the iterator in turn to see if it's contained in the
     * specified collection. If it's so contained, it's removed from this
     * collection with the iterator's <tt>remove</tt> method.<p>
     *
     * Note that this implementation will throw an
     * <tt>UnsupportedOperationException</tt> if the iterator returned by the
     * <tt>iterator</tt> method does not implement the <tt>remove</tt> method
     * and this collection contains one or more elements in common with the
     * specified collection.
     *
     * @param c elements to be removed from this collection.
     * @return <tt>true</tt> if this collection changed as a result of the call.
     * @throws UnsupportedOperationException if the <tt>removeAll</tt> method is
     * not supported by this collection.
     * @throws NullPointerException if the specified collection is null.
     *
     * @see #remove(Object)
     * @see #contains(Object)
     */
    public boolean removeAll(Collection c) {
        boolean modified = false;
        Iterator e = iterator();
        while (e.hasNext()) {
            if (c.contains(e.next())) {
                e.remove();
                modified = true;
            }
        }
        return modified;
    }

    /**
     * Retains only the elements in this collection that are contained in the
     * specified collection (optional operation). In other words, removes from
     * this collection all of its elements that are not contained in the
     * specified collection. <p>
     *
     * This implementation iterates over this collection, checking each element
     * returned by the iterator in turn to see if it's contained in the
     * specified collection. If it's not so contained, it's removed from this
     * collection with the iterator's <tt>remove</tt> method.<p>
     *
     * Note that this implementation will throw an
     * <tt>UnsupportedOperationException</tt> if the iterator returned by the
     * <tt>iterator</tt> method does not implement the <tt>remove</tt> method
     * and this collection contains one or more elements not present in the
     * specified collection.
     *
     * @param c elements to be retained in this collection.
     * @return <tt>true</tt> if this collection changed as a result of the call.
     * @throws UnsupportedOperationException if the <tt>retainAll</tt> method is
     * not supported by this Collection.
     * @throws NullPointerException if the specified collection is null.
     *
     * @see #remove(Object)
     * @see #contains(Object)
     */
    public boolean retainAll(Collection c) {
        boolean modified = false;
        Iterator e = iterator();
        while (e.hasNext()) {
            if (!c.contains(e.next())) {
                e.remove();
                modified = true;
            }
        }
        return modified;
    }

    /**
     * Removes all of the elements from this collection (optional operation).
     * The collection will be empty after this call returns (unless it throws an
     * exception).<p>
     *
     * This implementation iterates over this collection, removing each element
     * using the <tt>Iterator.remove</tt> operation. Most implementations will
     * probably choose to override this method for efficiency.<p>
     *
     * Note that this implementation will throw an
     * <tt>UnsupportedOperationException</tt> if the iterator returned by this
     * collection's <tt>iterator</tt> method does not implement the
     * <tt>remove</tt> method and this collection is non-empty.
     *
     * @throws UnsupportedOperationException if the <tt>clear</tt> method is not
     * supported by this collection.
     */
    public void clear() {
        Iterator e = iterator();
        while (e.hasNext()) {
            e.next();
            e.remove();
        }
    }

    //  String conversion
    /**
     * Returns a string representation of this collection. The string
     * representation consists of a list of the collection's elements in the
     * order they are returned by its iterator, enclosed in square brackets
     * (<tt>"[]"</tt>). Adjacent elements are separated by the characters <tt>",
     * "</tt> (comma and space). Elements are converted to strings as by
     * <tt>String.valueOf(Object)</tt>.<p>
     *
     * This implementation creates an empty string buffer, appends a left square
     * bracket, and iterates over the collection appending the string
     * representation of each element in turn. After appending each element
     * except the last, the string <tt>", "</tt> is appended. Finally a right
     * bracket is appended. A string is obtained from the string buffer, and
     * returned.
     *
     * @return a string representation of this collection.
     */
    public String toString() {
        StringBuffer buf = new StringBuffer();
        buf.append("[");

        Iterator i = iterator();
        boolean hasNext = i.hasNext();
        while (hasNext) {
            Object o = i.next();
            buf.append(o == this ? "(this Collection)" : String.valueOf(o));
            hasNext = i.hasNext();
            if (hasNext) {
                buf.append(", ");
            }
        }

        buf.append("]");
        return buf.toString();
    }
}
